package com.vhall.component.framework.core.loader;

import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * 自定义插件扩展机制，仅从 "META-INF/gateway/" 目录中查询插件类路径 每个插件必须实现插件属性注解 @PluginAttribute
 * ，否则不予加载和初始化
 *
 * @param <T>
 * @author xiaoliang.wang@vhall.com
 */
public class ExtensionPluginLoader<T> {

    private Class<T> type;
    private ClassLoader classLoader;
    private static final String PREFIX_NEURAL = "META-INF/vhall/";
    private static ConcurrentMap<Class<?>, ExtensionPluginLoader<?>> extensionLoaders = new ConcurrentHashMap<>();

    private ExtensionPluginLoader(Class<T> type, ClassLoader classLoader) {
        this.type = type;
        this.classLoader = classLoader;
    }

    protected static <T> ExtensionPluginLoader<T> getLoader(Class<T> type) {
        return getLoader(type, Thread.currentThread().getContextClassLoader());
    }

    @SuppressWarnings("unchecked")
    protected static <T> ExtensionPluginLoader<T> getLoader(Class<T> type, ClassLoader classLoader) {
        if (type == null) {
            throw new RuntimeException("Error extension type is null");
        }
        ExtensionPluginLoader<T> loader = (ExtensionPluginLoader<T>) extensionLoaders.get(type);
        if (loader == null) {
            loader = initExtensionLoader(type, classLoader);
        }

        return loader;
    }

    protected static synchronized <T> ExtensionPluginLoader<T> initExtensionLoader(Class<T> type) {
        return initExtensionLoader(type, Thread.currentThread().getContextClassLoader());
    }

    @SuppressWarnings("unchecked")
    protected static synchronized <T> ExtensionPluginLoader<T> initExtensionLoader(Class<T> type,
                                                                                   ClassLoader classLoader) {
        ExtensionPluginLoader<T> loader = (ExtensionPluginLoader<T>) extensionLoaders.get(type);
        if (loader == null) {
            loader = new ExtensionPluginLoader<>(type, classLoader);
            extensionLoaders.putIfAbsent(type, loader);
            loader = (ExtensionPluginLoader<T>) extensionLoaders.get(type);
        }

        return loader;
    }

    /**
     * 获取并初始化相关扩展插件的配置文件
     */
    protected List<CustomerExtension> getExtensionConfigs() {
        return this.loadExtensionConfigs(PREFIX_NEURAL);
    }

    /**
     * 在 prefix 路径下搜索配置文件
     *
     * @param prefix
     * @return
     */
    protected List<CustomerExtension> loadExtensionConfigs(String prefix) {
        List<CustomerExtension> result = new ArrayList<>(5);

        String fullName = prefix + type.getName();

        try {
            Enumeration<URL> urls;
            if (classLoader == null) {
                urls = ClassLoader.getSystemResources(fullName);
            } else {
                urls = classLoader.getResources(fullName);
            }

            if (urls == null || !urls.hasMoreElements()) {
                return result;
            }

            while (urls.hasMoreElements()) {
                URL url = urls.nextElement();
                CustomerExtension extension = new CustomerExtension(url, this.type, this.classLoader);
                result.add(extension);
            }
        } catch (Exception e) {
            throw new RuntimeException(
                    "ExtensionLoader loadExtension config files error, prefix: " + prefix + " type: " + type, e);
        }

        return result;
    }

}
